package com.xayy.health.mgt.service.impl;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.xayy.health.core.antlr4.model.ErrorResult;
import com.xayy.health.core.antlr4.utils.FunUtil;
import com.xayy.health.core.antlr4.utils.Golabl;
import com.xayy.health.core.antlr4.visitor.HealthEvaluateVisitor;
import com.xayy.health.core.enums.FaultFrequentEnum;
import com.xayy.health.core.enums.ScoreRuleEnum;
import com.xayy.health.mgt.model.*;
import com.xayy.health.mgt.model.vo.*;
import com.xayy.health.mgt.service.*;
import com.xayy.health.mgt.service.strategy.AlgorithmStrategy;
import com.xayy.health.mgt.service.strategy.HealthAlgorithmEnum;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.map.MapUtil;
import cn.kawins.base.result.CheckResult;
import cn.kawins.base.utils.*;
import cn.kawins.mybatis.base.BaseServiceImpl;
import tk.mybatis.mapper.entity.Example;

/**
 * 健康评估
 *
 * @author Nie
 * @version V1.0
 * @date 2023/4/10 10:21
 */
@Service
public class HealthAssessResultServiceImpl extends BaseServiceImpl<HealthAssessResult>
    implements HealthAssessResultService {

    @Autowired
    private SatelliteNodeService satelliteNodeService;

    @Autowired
    private HealthAssessRecordService healthAssessRecordService;

    @Autowired
    private FractionIntervalScoreService fractionIntervalScoreService;

    @Autowired
    private AssessParmaService assessParmaService;

    @Autowired
    private FaultInfoService faultInfoService;

    @Autowired
    private FaultScoreConfigService faultScoreConfigService;

    @Autowired
    private SatelliteCodeService satelliteCodeService;

    /**
     * 新增或更新节点分数
     *
     * @param healthAssessResult
     *            健康评估结果信息
     * @return 结果日志
     */
    @Override
    public CheckResult<?> updateAssessResult(HealthAssessResult healthAssessResult) {
        HealthAssessResult assessResult =
            selectOne(HealthAssessResult.builder().satelliteMid(healthAssessResult.getSatelliteMid())
                .parentId(healthAssessResult.getParentId()).nodeMid(healthAssessResult.getNodeMid()).build());
        if (Objects.nonNull(assessResult)) {
            healthAssessResult.setId(assessResult.getId());
        }
        healthAssessResult.setScoringRule(1);
        healthAssessResult.setFinishFraction(true);
        healthAssessResult.setFaultFactionIntroduction("手动故障评分为" + healthAssessResult.getFaultFraction() + "分。");
        healthAssessResult.setNatureFactionIntroduction("手动性能评分为" + healthAssessResult.getNatureFraction() + "分。");
        Integer faultFraction = healthAssessResult.getFaultFraction();
        Integer natureFraction = healthAssessResult.getNatureFraction();
        healthAssessResult.setMultipleFraction(
            getMultipleFraction(faultFraction, natureFraction, healthAssessResult.getFaultWeight() / 100D));
        healthAssessResult.setAutoScore(false);
        if (healthAssessResult.idValue() == null) {
            insertSelective(healthAssessResult);
        } else {
            updateByIdSelective(healthAssessResult);
        }
        HealthAssessRecord healthAssessRecord = buildRecord(healthAssessResult,
            String.valueOf(healthAssessResult.getSatelliteName()), healthAssessResult.getNodeName());
        healthAssessRecordService.insert(healthAssessRecord);
        return CheckResult.success(healthAssessResult);
    }

    /**
     * 查询节点分数
     * 
     * @param satelliteMid
     *            卫星id
     * @param satelliteName
     *            卫星名称
     * @param nodeMid
     *            节点id
     * @param parentId
     *            上级id
     * @return 结果日志
     */
    @Override
    public CheckResult<?> selectNodeScore(Long satelliteMid, String satelliteName, Long nodeMid, Long parentId) {
        HealthAssessResult assessResult =
            HealthAssessResult.builder().parentId(parentId).nodeMid(nodeMid).satelliteMid(satelliteMid).build();
        HealthAssessResult result = selectOne(assessResult);
        if (Objects.isNull(result)) {
            result = new HealthAssessResult();
            result.setParentId(parentId);
            result.setNodeMid(nodeMid);
            result.setSatelliteMid(satelliteMid);
            result.setSatelliteName(satelliteName);
            result.setFaultFraction(95);
            result.setNatureFraction(95);
            result.setMultipleFraction(95);
            result.setSatisfaction("健康");
            result.setFractionTime(new Date());
            result.setFaultWeight(80D);
            result.setScoringRule(2);
            result.setFaultFactionIntroduction("手动故障评分为95分。");
            result.setNatureFactionIntroduction("手动性能评分为95分。");
            result.setEvaluatingWeight(0D);
            insertSelective(result);
            HealthAssessRecord healthAssessRecord =
                buildRecord(result, String.valueOf(result.getSatelliteName()), result.getNodeName());
            healthAssessRecordService.insert(healthAssessRecord);
        }
        // 权重和校验信息
        Map<String, Object> data = getWeightMsg(result).getData();
        HealthAssessResultVo healthAssessResultVo = BeanUtil.copyBean(result, HealthAssessResultVo.class);
        healthAssessResultVo.setWeightMsg((String)data.get("weightMsg"));
        healthAssessResultVo.setMaxWeight((Double)data.get("maxWeight"));
        return CheckResult.success(healthAssessResultVo);
    }

    /**
     * 计算根节点分数
     * 
     * @param calculateVo
     *            入参信息
     * @return 结果信息
     */
    @Override
    public CheckResult<?> calculate(CalculateVo calculateVo) {
        if (BeanUtil.isEmpty(calculateVo.getFractionTime())) {
            return CheckResult.fail("请在卫星节点配置评估时间");
        }
        AlgorithmStrategy<HealthAssessParam> healthStrategy =
            HealthAlgorithmEnum.mathAlgorithm(calculateVo.getAlgorithmType());
        if (Objects.isNull(healthStrategy)) {
            return CheckResult.fail("未匹配到相关算法");
        }
        /*查询卫星只是拓扑结构*/
        SatelliteNode satellite =
            SatelliteNode.builder().id(calculateVo.getSatelliteId()).xing(calculateVo.getSatelliteName()).build();
        // 卫星
        List<SatelliteNodeTreeVo> satelliteNodeList = satelliteNodeService.getTreeList(satellite);
        Map<Long, List<SatelliteNodeTreeVo>> satMap =
            satelliteNodeList.stream().collect(Collectors.groupingBy(SatelliteNodeTreeVo::getId));
        List<SatelliteNodeTreeVo> treeVoList = cn.kawins.base.utils.TreeUtil.toTree(0L, satelliteNodeList);
        SatelliteNodeTreeVo defRoot = treeVoList.get(0);
        if (BeanUtil.isEmpty(defRoot)) {
            return CheckResult.fail("没有获取到卫星结构信息");
        }

        // =============================================
        List<HealthAssessResult> assessResults =
            select(HealthAssessResult.builder().satelliteMid(calculateVo.getSatelliteId()).build());
        // 最新的节点mid集合
        Set<Long> currentMidList =
            satelliteNodeList.stream().map(SatelliteNodeTreeVo::getId).collect(Collectors.toSet());
        // 库里的已经评分过的mid集合
        Set<Long> dbMidList = assessResults.stream().map(HealthAssessResult::getNodeMid).collect(Collectors.toSet());
        // 库里有评分，但是获取的最新节点里没有的，证明装备画像那边已经删除节点，需要从评分库删除，防止脏数据
        List<Long> delIds = assessResults.stream().map(HealthAssessResult::getNodeMid)
            .filter(aLong -> !currentMidList.contains(aLong)).collect(Collectors.toList());
        deleteByIds(delIds);
        // 从数据库删除的评分数据也需要从刚才查询出来的list中删除
        assessResults.removeIf(x -> delIds.contains(x.getId()));

        // 库里没有评分的节点list，此部分节点需要在库里插入评分信息
        List<SatelliteNodeTreeVo> dataList =
            satelliteNodeList.stream().filter(x -> !dbMidList.contains(x.getId())).collect(Collectors.toList());

        List<CalculateNodeVo> calculateNodeVoList = dataList.stream().map(x -> {
            CalculateNodeVo calculateNodeVo = new CalculateNodeVo();
            calculateNodeVo.setSatId(calculateVo.getSatelliteId());
            calculateNodeVo.setSatName(calculateVo.getSatelliteName());
            calculateNodeVo.setParentId(x.getPid());
            calculateNodeVo.setComponentId(x.getId());
            calculateNodeVo.setComponentName(x.getName());
            calculateNodeVo.setFractionTime(calculateVo.getFractionTime());
            calculateNodeVo.setFractionStartTime(calculateVo.getFractionStartTime());
            return calculateNodeVo;
        }).collect(Collectors.toList());

        // 找到需要规则打分的节点，新增的全部规则打分加上库里配了规则打分的节点
        List<HealthAssessResult> collect =
            assessResults.stream().filter(x -> x.getScoringRule() == 2).collect(Collectors.toList());
        List<CalculateNodeVo> ruleList = collect.stream().map(x -> {
            CalculateNodeVo calculateNodeVo = new CalculateNodeVo();
            calculateNodeVo.setSatId(calculateVo.getSatelliteId());
            calculateNodeVo.setSatName(calculateVo.getSatelliteName());
            calculateNodeVo.setComponentId(x.getNodeMid());
            calculateNodeVo.setComponentName(x.getNodeName());
            calculateNodeVo.setFractionStartTime(calculateVo.getFractionStartTime());
            List<SatelliteNodeTreeVo> satelliteNodeTreeVos = satMap.get(x.getNodeMid());
            if (CollUtil.isNotEmpty(satelliteNodeTreeVos)) {
                calculateNodeVo.setComponentName(satelliteNodeTreeVos.get(0).getName());
            }
            calculateNodeVo.setFractionTime(calculateVo.getFractionTime());
            return calculateNodeVo;
        }).collect(Collectors.toList());
        ruleList.addAll(calculateNodeVoList);
        // 规则打分
        ThreadPoolExecutor threadPoolExecutor = ThreadUtil.newExecutor(50, 200);
        // 对未打分的节点走规则打分
        SatelliteCode satelliteCode = satelliteCodeService
            .selectOne(SatelliteCode.builder().satelliteId(String.valueOf(calculateVo.getSatelliteId())).build());
        if (BeanUtil.isEmpty(satelliteCode)) {
            return CheckResult.fail("卫星code不存在");
        }
        HealthEvaluateVisitor visitor =
            new HealthEvaluateVisitor(satelliteCode.getSatelliteCode(), calculateVo.getFractionTime());
        ruleList.forEach(x -> threadPoolExecutor.submit(() -> regularScoring(x, visitor)));
        ThreadUtil.awaitEnd(60, threadPoolExecutor);
        List<HealthAssessResult> healthAssessResultList =
            select(HealthAssessResult.builder().satelliteMid(calculateVo.getSatelliteId()).build());

        List<SatelliteNodeTreeVo> tree = TreeUtil.toTree(calculateVo.getSatelliteId(), satelliteNodeList);
        return healthStrategy.process(HealthAssessParam.builder().mid(calculateVo.getSatelliteId()).list(tree)
            .assessResults(healthAssessResultList).satelliteName(calculateVo.getSatelliteName()).build());
        // =============================================
    }

    /**
     * 记录
     *
     * @param healthAssessResult
     *            健康评估
     * @param satelliteName
     *            卫星名称
     * @param componentName
     *            部件名称
     * @return HealthAssessRecord
     */
    public static HealthAssessRecord buildRecord(HealthAssessResult healthAssessResult, String satelliteName,
        String componentName) {
        Long satelliteMid = healthAssessResult.getSatelliteMid();
        return HealthAssessRecord.builder().satelliteMid(satelliteMid).satelliteName(satelliteName)
            .parentId(healthAssessResult.getParentId()).componentMid(healthAssessResult.getNodeMid())
            .componentName(componentName).algorithmName("层次分析法").faultScore(healthAssessResult.getFaultFraction())
            .performanceScore(healthAssessResult.getNatureFraction())
            .healthScore(healthAssessResult.getMultipleFraction()).healthLevel("健康")
            .fractionTime(healthAssessResult.getFractionTime()).build();
    }

    /**
     * 获取健康评估算法下拉框列表
     *
     * @return 结果信息
     */
    @Override
    public CheckResult<?> spinner() {
        return CheckResult.success(MapUtil.builder().put("healthAlgorithmEnum", HealthAlgorithmEnum.list()).build());
    }

    /**
     * 查询节所有最底层节点是否完成打分
     *
     * @param satelliteMid
     *            卫星id
     * @return 结果日志
     */
    @Override
    public CheckResult<?> checkChildScore(Long satelliteMid) {
        Map<String, Object> paramMap = new HashMap<>(1);
        paramMap.put("rootId", satelliteMid);
        List<SatelliteNodeTreeVo> satelliteNodeList = satelliteNodeService.getSatelliteNodeList(satelliteMid);
        if (CollUtil.isNotEmpty(satelliteNodeList)) {
            List<HealthAssessResult> assessResults =
                select(HealthAssessResult.builder().satelliteMid(satelliteMid).build());
            // 库里的已经评分过的mid集合
            List<Long> dbMidList =
                assessResults.stream().map(HealthAssessResult::getNodeMid).collect(Collectors.toList());
            // 库里没有评分的节点list，此部分节点需要在库里插入评分信息
            Map<Long, String> dataMap = satelliteNodeList.stream().filter(x -> !dbMidList.contains(x.getId()))
                .collect(Collectors.toMap(SatelliteNodeTreeVo::getId, SatelliteNodeTreeVo::getName));
            MapBuilder<String, Object> builder = MapUtil.<String, Object>builder().put("notRated", dataMap);
            if (dataMap.isEmpty()) {
                builder.put("isAllRated", true);
                return CheckResult.success(builder.build());
            } else {
                builder.put("isAllRated", false);
                builder.put("msg", "有部分部件未完成评分，如果继续评估，未打分部件将以0分计算");
                return CheckResult.success(builder.build());
            }
        } else {
            return CheckResult.fail("从知识图谱获取节点信息失败，未进行评估");
        }
    }

    /**
     * 计算叶子节点故障分数
     * 
     * @param calculateNodeVo
     *            入参信息
     * @return 结果日志
     */
    @Override
    public CheckResult<Object> calculateNodeFault(CalculateNodeVo calculateNodeVo) {
        if (BeanUtil.isEmpty(calculateNodeVo.getFractionTime())) {
            return CheckResult.fail("请在卫星节点配置评估时间");
        }
        HealthAssessResult healthAssessResult =
            selectOne(HealthAssessResult.builder().satelliteMid(calculateNodeVo.getSatId())
                .parentId(calculateNodeVo.getParentId()).nodeMid(calculateNodeVo.getComponentId()).build());
        // 计算故障分值
        List<FaultInfo> faultInfos =
            faultInfoService.selectByArgs(calculateNodeVo.getSatId(), calculateNodeVo.getComponentId(),
                calculateNodeVo.getFractionTime(), calculateNodeVo.getFractionStartTime()).getData();
        Integer score = autoCalculateFaultScore(faultInfos);
        // 获取打分日志
        String faultMsg =
            faultRule(faultInfos, score, calculateNodeVo.getComponentName(), calculateNodeVo.getFractionTime());
        if (Objects.nonNull(healthAssessResult)) {
            healthAssessResult.setFaultFraction(score);
            healthAssessResult.setMultipleFraction(getMultipleFraction(score, healthAssessResult.getNatureFraction(),
                healthAssessResult.getFaultWeight() / 100D));
            healthAssessResult.setAutoScore(true);
            healthAssessResult.setFractionTime(new Date());
            healthAssessResult.setScoringRule(2);
            healthAssessResult.setFaultFactionIntroduction(faultMsg);
            HealthAssessRecord healthAssessRecord =
                buildRecord(healthAssessResult, calculateNodeVo.getComponentName(), calculateNodeVo.getSatName());
            healthAssessRecordService.insert(healthAssessRecord);
            updateByIdSelective(healthAssessResult);
            return CheckResult.success(healthAssessResult);
        } else {

            HealthAssessResult result = HealthAssessResult.builder().satelliteMid(calculateNodeVo.getSatId())
                .multipleFraction(getMultipleFraction(score, 95, 0.8)).faultFraction(score).natureFraction(95)
                .fractionTime(new Date()).isComponent(true).finishFraction(true).autoScore(true)
                .parentId(calculateNodeVo.getParentId()).nodeMid(calculateNodeVo.getComponentId()).scoringRule(2)
                .faultFactionIntroduction(faultMsg).build();
            insertSelective(result);
            HealthAssessRecord healthAssessRecord =
                buildRecord(result, calculateNodeVo.getSatName(), calculateNodeVo.getComponentName());
            healthAssessRecordService.insert(healthAssessRecord);
            return CheckResult.success(result);
        }
    }

    /**
     * 规则打分
     *
     * @param calculateNodeVo
     *            入参
     */
    private void regularScoring(CalculateNodeVo calculateNodeVo, HealthEvaluateVisitor visitor) {

        String satisfaction = "无";
        // 计算故障分值
        List<FaultInfo> faultInfos =
            faultInfoService.selectByArgs(calculateNodeVo.getSatId(), calculateNodeVo.getComponentId(),
                calculateNodeVo.getFractionTime(), calculateNodeVo.getFractionStartTime()).getData();
        Integer faultScore = autoCalculateFaultScore(faultInfos);
        if (faultScore == null) {
            faultScore = 100;
        }
        // 获取打分日志
        String faultMsg =
            faultRule(faultInfos, faultScore, calculateNodeVo.getComponentName(), calculateNodeVo.getFractionTime());

        // 性能评分
        Integer performanceScore = autoCalculatePerformanceScore(calculateNodeVo.getSatId(),
            calculateNodeVo.getParentId(), calculateNodeVo.getComponentId(), visitor);
        // 获取性能打分日志
        if (performanceScore == null) {
            performanceScore = 100;
        }
        // 性能打分日志
        String natureMsg = calculateRule(calculateNodeVo, performanceScore);
        CheckResult<FractionIntervalScoreVo> fractionResult =
            fractionIntervalScoreService.selectByType(ScoreRuleEnum.HEALTH.getCode());

        HealthAssessResult healthAssessResult =
            selectOne(HealthAssessResult.builder().satelliteMid(calculateNodeVo.getSatId())
                .parentId(calculateNodeVo.getParentId()).nodeMid(calculateNodeVo.getComponentId()).build());
        if (Objects.nonNull(healthAssessResult)) {
            int multipleFraction =
                getMultipleFraction(faultScore, performanceScore, healthAssessResult.getFaultWeight() / 100D);
            if (fractionResult.isSuccess()) {
                satisfaction =
                    ScoreRuleEnum.matchLevelStr(fractionResult.getData().getIntervalList(), multipleFraction);
            }
            healthAssessResult.setFaultFraction(faultScore);
            healthAssessResult.setNatureFraction(performanceScore);
            healthAssessResult.setMultipleFraction(multipleFraction);
            healthAssessResult.setAutoScore(true);
            healthAssessResult.setFractionTime(new Date());
            healthAssessResult.setSatisfaction(satisfaction);
            healthAssessResult.setScoringRule(2);
            healthAssessResult.setFaultFactionIntroduction(faultMsg);
            healthAssessResult.setNatureFactionIntroduction(natureMsg);
            updateByIdSelective(healthAssessResult);

        } else {
            int multipleFraction = getMultipleFraction(faultScore, performanceScore, 0.8D);
            if (fractionResult.isSuccess()) {
                satisfaction =
                    ScoreRuleEnum.matchLevelStr(fractionResult.getData().getIntervalList(), multipleFraction);
            }
            HealthAssessResult result = HealthAssessResult.builder().satelliteMid(calculateNodeVo.getSatId())
                .multipleFraction(multipleFraction).faultFraction(faultScore).natureFraction(performanceScore)
                .faultWeight(80D).fractionTime(new Date()).isComponent(true).finishFraction(true).autoScore(true)
                .parentId(calculateNodeVo.getParentId()).nodeMid(calculateNodeVo.getComponentId())
                .satisfaction(satisfaction).scoringRule(2).faultFactionIntroduction(faultMsg)
                .natureFactionIntroduction(natureMsg).evaluatingWeight(0D).build();
            insertSelective(result);
        }

    }

    /**
     * 自动计算故障分值
     *
     * @param faultInfos
     *            故障信息
     * @return Integer
     */
    public Integer autoCalculateFaultScore(List<FaultInfo> faultInfos) {
        Map<Integer, List<FaultInfo>> collect =
            faultInfos.stream().collect(Collectors.groupingBy(FaultInfo::getFaultLevel));
        Optional<Integer> optional = collect.keySet().stream().max(Integer::compareTo);
        int max = 0;
        if (optional.isPresent()) {
            max = optional.get();
        }
        int num = 0;
        if (CollUtil.isNotEmpty(collect.get(max))) {
            num = collect.get(max).size();
        }
        return matchScore(max, num);
    }

    /**
     * 匹配分值
     *
     * @param level
     *            级别
     * @param num
     *            数字
     * @return Integer
     */
    private Integer matchScore(int level, int num) {
        Integer score = 95;
        // 根据故障数目去获取故障的发生频度
        String keyName = FaultFrequentEnum.getKeyName(num);
        FaultScoreConfig data = faultScoreConfigService.selectScoreByKey(keyName, String.valueOf(level)).getData();
        if (BeanUtil.isNotEmpty(data)) {
            score = data.getScore();
        }
        return score;
    }

    /**
     * 故障规则
     *
     * @param faultInfos
     *            故障信息
     * @param score
     *            分值
     * @param componentName
     *            部件名称
     * @param time
     *            时间
     * @return String
     */
    public String faultRule(List<FaultInfo> faultInfos, Integer score, String componentName, Date time) {
        String faultMsg;
        if (CollUtil.isEmpty(faultInfos)) {
            return "部件" + componentName + "在轨运行至：" + DateUtil.format(time, "yyyy-MM-dd HH:mm:ss") + "时间段内发生故障共计0次,最终评分为"
                + score + "分。";
        }
        Map<Integer, List<FaultInfo>> collect =
            faultInfos.stream().collect(Collectors.groupingBy(FaultInfo::getFaultLevel));
        Integer num1 = CollUtil.isEmpty(collect.get(1)) ? 0 : collect.get(1).size();
        Integer num2 = CollUtil.isEmpty(collect.get(2)) ? 0 : collect.get(2).size();
        Integer num3 = CollUtil.isEmpty(collect.get(3)) ? 0 : collect.get(3).size();
        Integer num4 = CollUtil.isEmpty(collect.get(4)) ? 0 : collect.get(4).size();

        faultMsg = "部件" + componentName + "在轨运行至" + DateUtil.format(time, "yyyy-MM-dd HH:mm:ss") + "时间段内发生故障共计"
            + faultInfos.size() + "次，其中，轻微故障" + num1 + "次，一般故障" + num2 + "次，严重故障" + num3 + "次，致命故障" + num4
            + "次，满足评分规则，最终评分为" + score + "分。";
        return faultMsg;
    }

    /**
     * 计算叶子节点性能分数
     * 
     * @param calculateNodeVo
     *            入参信息
     * @return 结果日志
     */
    @Override
    public CheckResult<Object> calculateNodePerformance(CalculateNodeVo calculateNodeVo) {
        if (BeanUtil.isEmpty(calculateNodeVo.getFractionTime())) {
            return CheckResult.fail("请在卫星节点配置评估时间");
        }
        // 性能打分
        Integer score;
        score = autoCalculatePerformanceScore(calculateNodeVo.getSatId(), calculateNodeVo.getSystemId(),
            calculateNodeVo.getNodeId(), calculateNodeVo.getFractionTime());
        // 性能打分日志
        String natureMsg = calculateRule(calculateNodeVo, score);
        HealthAssessResult healthAssessResult =
            selectOne(HealthAssessResult.builder().satelliteMid(calculateNodeVo.getSatId())
                .parentId(calculateNodeVo.getParentId()).nodeMid(calculateNodeVo.getComponentId()).build());
        if (Objects.nonNull(healthAssessResult)) {
            healthAssessResult.setFractionTime(new Date());
            HealthAssessRecord healthAssessRecord =
                buildRecord(healthAssessResult, calculateNodeVo.getSatName(), calculateNodeVo.getComponentName());
            healthAssessRecordService.insert(healthAssessRecord);
            healthAssessResult.setNatureFraction(score);
            healthAssessResult.setMultipleFraction(getMultipleFraction(healthAssessResult.getFaultFraction(), score,
                healthAssessResult.getFaultWeight() / 100D));
            healthAssessResult.setAutoScore(true);
            healthAssessResult.setScoringRule(2);
            healthAssessResult.setNatureFactionIntroduction(natureMsg);
            updateByIdSelective(healthAssessResult);
            return CheckResult.success(healthAssessResult);
        } else {
            HealthAssessResult result = HealthAssessResult.builder().satelliteMid(calculateNodeVo.getSatId())
                .multipleFraction(getMultipleFraction(95, score, 0.8)).natureFraction(score).faultFraction(95)
                .fractionTime(new Date()).isComponent(true).autoScore(true).parentId(calculateNodeVo.getParentId())
                .nodeMid(calculateNodeVo.getComponentId()).scoringRule(2).natureFactionIntroduction(natureMsg).build();
            insertSelective(result);
            HealthAssessRecord healthAssessRecord =
                buildRecord(result, calculateNodeVo.getSatName(), calculateNodeVo.getComponentName());
            healthAssessRecordService.insert(healthAssessRecord);
            return CheckResult.success(result);
        }
    }

    @Override
    public CheckResult<Object> calculateSystemPerformance(CalculateNodeVo calculateNodeVo) {
        // 分系统
        calculateNodeVo.setSystemId(calculateNodeVo.getComponentId());
        calculateNodeVo.setNodeId(null);

        if (BeanUtil.isEmpty(calculateNodeVo.getFractionTime())) {
            return CheckResult.fail("请在卫星节点配置评估时间");
        }
        // 性能打分
        Integer score;
        score = autoCalculatePerformanceScore(calculateNodeVo.getSatId(), calculateNodeVo.getSystemId(),
            calculateNodeVo.getNodeId(), calculateNodeVo.getFractionTime());
        // 性能打分日志
        String natureMsg = calculateRule(calculateNodeVo, score);
        HealthAssessResult healthAssessResult =
            selectOne(HealthAssessResult.builder().satelliteMid(calculateNodeVo.getSatId())
                .parentId(calculateNodeVo.getParentId()).nodeMid(calculateNodeVo.getComponentId()).build());
        if (Objects.nonNull(healthAssessResult)) {
            healthAssessResult.setFractionTime(new Date());
            HealthAssessRecord healthAssessRecord =
                buildRecord(healthAssessResult, calculateNodeVo.getSatName(), calculateNodeVo.getComponentName());
            healthAssessRecordService.insert(healthAssessRecord);
            healthAssessResult.setNatureFraction(score);
            healthAssessResult.setMultipleFraction(score);
            healthAssessResult.setAutoScore(true);
            healthAssessResult.setScoringRule(2);
            healthAssessResult.setNatureFactionIntroduction(natureMsg);
            updateByIdSelective(healthAssessResult);
            return CheckResult.success(healthAssessResult);
        } else {
            HealthAssessResult result = HealthAssessResult.builder().satelliteMid(calculateNodeVo.getSatId())
                .multipleFraction(score).natureFraction(score).faultFraction(0).faultWeight(0D).fractionTime(new Date())
                .isComponent(false).autoScore(true).parentId(calculateNodeVo.getParentId())
                .nodeMid(calculateNodeVo.getComponentId()).scoringRule(2).natureFactionIntroduction(natureMsg).build();
            insertSelective(result);
            HealthAssessRecord healthAssessRecord =
                buildRecord(result, calculateNodeVo.getSatName(), calculateNodeVo.getComponentName());
            healthAssessRecordService.insert(healthAssessRecord);
            return CheckResult.success(result);
        }
    }

    @Override
    public CheckResult<Object> calculateSatellitePerformance(CalculateNodeVo calculateNodeVo) {
        calculateNodeVo.setSystemId(null);
        calculateNodeVo.setNodeId(null);
        if (BeanUtil.isEmpty(calculateNodeVo.getFractionTime())) {
            return CheckResult.fail("请在卫星节点配置评估时间");
        }
        // 性能打分
        Integer score = 100;
        score = autoCalculatePerformanceScore(calculateNodeVo.getSatId(), calculateNodeVo.getSystemId(),
            calculateNodeVo.getNodeId(), calculateNodeVo.getFractionTime());
        // 性能打分日志
        String natureMsg = calculateRule(calculateNodeVo, score);
        HealthAssessResult healthAssessResult =
            selectOne(HealthAssessResult.builder().satelliteMid(calculateNodeVo.getSatId())
                .parentId(calculateNodeVo.getParentId()).nodeMid(calculateNodeVo.getComponentId()).build());
        if (Objects.nonNull(healthAssessResult)) {
            healthAssessResult.setFractionTime(new Date());
            HealthAssessRecord healthAssessRecord =
                buildRecord(healthAssessResult, calculateNodeVo.getSatName(), calculateNodeVo.getComponentName());
            healthAssessRecordService.insert(healthAssessRecord);
            healthAssessResult.setNatureFraction(score);
            healthAssessResult.setMultipleFraction(score);
            healthAssessResult.setAutoScore(true);
            healthAssessResult.setScoringRule(2);
            healthAssessResult.setNatureFactionIntroduction(natureMsg);
            updateByIdSelective(healthAssessResult);
            return CheckResult.success(healthAssessResult);
        } else {
            HealthAssessResult result = HealthAssessResult.builder().satelliteMid(calculateNodeVo.getSatId())
                .multipleFraction(score).natureFraction(score).faultFraction(0).faultWeight(0D).fractionTime(new Date())
                .isComponent(false).autoScore(true).parentId(calculateNodeVo.getParentId())
                .nodeMid(calculateNodeVo.getComponentId()).scoringRule(2).natureFactionIntroduction(natureMsg).build();
            insertSelective(result);
            HealthAssessRecord healthAssessRecord =
                buildRecord(result, calculateNodeVo.getSatName(), calculateNodeVo.getComponentName());
            healthAssessRecordService.insert(healthAssessRecord);
            return CheckResult.success(result);
        }
    }

    /**
     * 自动计算性能分值
     *
     * @param satId
     *            卫星id
     * @param nodeId
     *            节点id
     * @param time
     *            时间
     * @return Integer
     */
    public Integer autoCalculatePerformanceScore(Long satId, Long systemId, Long nodeId, Date time) {
        // 查询该节点的健康评估模型
        List<AssessParma> assessParmaList =
            assessParmaService.getAssessParmaListBySat(satId, systemId, nodeId).getData();
        if (CollUtil.isNotEmpty(assessParmaList)) {
            SatelliteCode satelliteCode =
                satelliteCodeService.selectOne(SatelliteCode.builder().satelliteId(String.valueOf(satId)).build());
            if (BeanUtil.isEmpty(satelliteCode)) {
                return 95;
            }
            double so = 0D;
            HealthEvaluateVisitor visitor = new HealthEvaluateVisitor(satelliteCode.getSatelliteCode(), time);
            for (AssessParma assessParma : assessParmaList) {
                ErrorResult execute = FunUtil.execute(assessParma.getVisitor(), visitor);
                if (execute.isSuccess()) {
                    Double a = execute.getResult();
                    a = a < 0 ? 0 : a;
                    a = a > 100 ? 100 : a;
                    so += a;
                }
            }
            so = so / assessParmaList.size();
            // 清理缓存
            Golabl.clear(satelliteCode.getSatelliteCode());
            Golabl.clearXn(satelliteCode.getSatelliteCode());
            return (int)so;
        }
        return 95;
    }

    /**
     * 根节点自动计算性能分值
     *
     * @param satId
     *            卫星id
     * @param nodeId
     *            节点id
     * @return Integer
     */
    public Integer autoCalculatePerformanceScore(Long satId, Long systemId, Long nodeId,
        HealthEvaluateVisitor visitor) {
        // 查询该节点的健康评估模型
        List<AssessParma> assessParmaList =
            assessParmaService.getAssessParmaListBySat(satId, systemId, nodeId).getData();
        if (CollUtil.isNotEmpty(assessParmaList)) {
            SatelliteCode satelliteCode =
                satelliteCodeService.selectOne(SatelliteCode.builder().satelliteId(String.valueOf(satId)).build());
            if (BeanUtil.isEmpty(satelliteCode)) {
                return 95;
            }
            double so = 0D;
            for (AssessParma assessParma : assessParmaList) {
                ErrorResult execute = FunUtil.execute(assessParma.getVisitor(), visitor);
                if (execute.isSuccess()) {
                    Double a = execute.getResult();
                    a = a < 0 ? 0 : a;
                    a = a > 100 ? 100 : a;
                    so += a;
                }
            }
            so = so / assessParmaList.size();
            // 清理缓存
            Golabl.clear(satelliteCode.getSatelliteCode());
            Golabl.clearXn(satelliteCode.getSatelliteCode());
            return (int)so;
        }
        return 95;
    }

    /**
     * 查询选中节点的图表信息
     * 
     * @param satId
     *            卫星id
     * @param nodeMid
     *            节点id
     * @param parentId
     *            上级id
     * @return 结果日志
     */
    @Override
    public CheckResult<List<HealthAssessRecord>> selectNodeInfo(Long satId, Long nodeMid, Long parentId) {
        if (BeanUtil.isEmpty(satId)) {
            return CheckResult.success();
        }
        Example example = new Example(HealthAssessRecord.class);
        example.orderBy("fractionTime");
        example.createCriteria().andEqualTo("satelliteMid", satId).andEqualTo("componentMid", nodeMid)
            .andEqualTo("parentId", parentId);
        return CheckResult.success(healthAssessRecordService.selectByExample(example));
    }

    /**
     * 计算规则
     *
     * @param calculateNodeVo
     *            入参
     * @param score
     *            分值
     * @return String
     */
    public String calculateRule(CalculateNodeVo calculateNodeVo, Integer score) {
        List<AssessParma> assessParmaList = assessParmaService.getAssessParmaListBySat(calculateNodeVo.getSatId(),
            calculateNodeVo.getParentId(), calculateNodeVo.getComponentId()).getData();
        TreeSet<String> params = new TreeSet<>();
        String param = null;
        if (CollUtil.isNotEmpty(assessParmaList)) {
            for (AssessParma assessParma : assessParmaList) {
                params.addAll(assessParma.getParamList());
            }
            param = StringUtil.join(",", params);
        }
        if (param == null) {
            String natureMsg = calculateNodeVo.getComponentName() + "没有配置评估模型,取默认评分为" + score + "分。";
            return natureMsg;
        }
        String natureMsg = calculateNodeVo.getComponentName() + "使用"
            + DateUtil.format(calculateNodeVo.getFractionStartTime(), "yyyy-MM-dd HH:mm:ss") + "到"
            + DateUtil.format(calculateNodeVo.getFractionTime(), "yyyy-MM-dd HH:mm:ss") + "时间段内遥测参数" + param
            + "，利用评估模型进行评估，最终评分为" + score + "分。";
        return natureMsg;
    }

    /**
     * 修改部件节点打分类型
     * 
     * @param healthAssessResult
     *            入参信息
     * @return 结果日志
     */
    @Transactional
    @Override
    public CheckResult<Object> updateStatus(HealthAssessResult healthAssessResult) {
        if (BeanUtil.isEmpty(healthAssessResult.getSatelliteMid())) {
            return CheckResult.fail("卫星节点id不能为空");
        }
        if (BeanUtil.isEmpty(healthAssessResult.getNodeMid())) {
            return CheckResult.fail("部件节点id不能为空");
        }
        HealthAssessResult assessResult =
            selectOne(HealthAssessResult.builder().satelliteMid(healthAssessResult.getSatelliteMid())
                .parentId(healthAssessResult.getParentId()).nodeMid(healthAssessResult.getNodeMid()).build());
        if (Objects.nonNull(assessResult)) {
            healthAssessResult.setId(assessResult.getId());
        }
        healthAssessResult.setScoringRule(healthAssessResult.getScoringRule());
        if (healthAssessResult.idValue() == null) {
            insertSelective(healthAssessResult);
        } else {
            updateByIdSelective(healthAssessResult);
        }
        return CheckResult.success(healthAssessResult);
    }

    /**
     * 修改节点信息权重信息
     * 
     * @param healthAssessResult
     *            入参信息
     * @return 结果日志
     */
    @Override
    public CheckResult<Object> updateWeight(HealthAssessResult healthAssessResult) {
        HealthAssessResult result =
            selectOne(HealthAssessResult.builder().satelliteMid(healthAssessResult.getSatelliteMid())
                .parentId(healthAssessResult.getParentId()).nodeMid(healthAssessResult.getNodeMid()).build());
        if (BeanUtil.isEmpty(result)) {
            return CheckResult.fail("修改节点性能权重失败");
        }
        Double evaluatingWeight = healthAssessResult.getEvaluatingWeight();
        // DecimalFormat df = new DecimalFormat("#.00");
        // Double aDouble = Double.valueOf(df.format(evaluatingWeight));
        Example example = new Example(HealthAssessResult.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("satelliteMid", healthAssessResult.getSatelliteMid());
        criteria.andEqualTo("parentId", healthAssessResult.getParentId());
        criteria.andNotEqualTo("nodeMid", healthAssessResult.getNodeMid());
        List<HealthAssessResult> healthAssessResults = selectByExample(example);
        BigDecimal sum = BigDecimal.valueOf(0);
        if (CollUtil.isNotEmpty(healthAssessResults)) {
            for (HealthAssessResult assessResult : healthAssessResults) {
                sum = sum.add(BigDecimal.valueOf(assessResult.getEvaluatingWeight()));
            }
        }
        BigDecimal sum1 = sum.add(BigDecimal.valueOf(evaluatingWeight));
        if (sum1.doubleValue() > 1D) {
            BigDecimal a = BigDecimal.valueOf(1);
            BigDecimal subtract = a.subtract(sum);
            return CheckResult.fail("节点可配置权限范围为0--" + subtract);
        }
        result.setEvaluatingWeight(evaluatingWeight);
        updateByIdSelective(result);
        return CheckResult.success();
    }

    /**
     * 获取权重和日志信息
     *
     * @param healthAssessResult
     *            入参信息
     * @return 结果日志
     */
    @Override
    public CheckResult<Map<String, Object>> getWeightMsg(HealthAssessResult healthAssessResult) {
        Map<String, Object> result = new HashMap<>(2);
        Example example = new Example(HealthAssessResult.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("satelliteMid", healthAssessResult.getSatelliteMid());
        criteria.andEqualTo("parentId", healthAssessResult.getParentId());
        criteria.andNotEqualTo("nodeMid", healthAssessResult.getNodeMid());
        List<HealthAssessResult> healthAssessResults = selectByExample(example);
        if (CollUtil.isNotEmpty(healthAssessResults)) {
            BigDecimal sum = BigDecimal.valueOf(healthAssessResult.getEvaluatingWeight());
            for (HealthAssessResult assessResult : healthAssessResults) {
                sum = sum.add(BigDecimal.valueOf(assessResult.getEvaluatingWeight()));
            }
            BigDecimal a = BigDecimal.valueOf(1);
            BigDecimal subtract = a.subtract(sum);
            result.put("weightMsg", "当前节点的同级节点已配权重和为：" + sum + ";可分配权重为0--" + subtract.toPlainString() + "。");
            // result.put("maxWeight", subtract.doubleValue());
            result.put("maxWeight", 1D);

            return CheckResult.success(result);
        }
        result.put("weightMsg", "当前节点的同级节点已配权重和为：0;可分配权重为0--1。");
        result.put("maxWeight", 1D);
        return CheckResult.success(result);
    }

    /**
     * 计算综合评分
     * 
     * @param faultFraction
     *            故障分数
     * @param natureFraction
     *            性能分数
     * @param natureFraction
     *            故障权重
     * @return 综合评分
     */
    public int getMultipleFraction(Integer faultFraction, Integer natureFraction, Double faultWeight) {
        if (Objects.isNull(faultFraction)) {
            faultFraction = 0;
        }
        if (Objects.isNull(natureFraction)) {
            natureFraction = 0;
        }
        long round = Math.round(faultFraction * faultWeight + natureFraction * (1 - faultWeight));
        return (int)round;
    }

}
